package com.lxq.particledemo02;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import android.graphics.Color;
import android.opengl.GLES20;

public class ParticleSystem {

    private static final int BYTES_PER_FLOAT = 4;
    private static final int POSITION_COMPONENT_COUNT = 3;
    private static final int COLOR_COMPONENT_COUNT = 3;
    private static final int VECTOR_COMPONENT_COUNT = 3;
    private static final int PARTICLE_START_TIME_COMPONENT_COUNT = 1;
    private static final int TOTAL_COMPONENT_COUNT = POSITION_COMPONENT_COUNT
            + COLOR_COMPONENT_COUNT + VECTOR_COMPONENT_COUNT
            + PARTICLE_START_TIME_COMPONENT_COUNT;
    private static final int STRIDE = TOTAL_COMPONENT_COUNT * BYTES_PER_FLOAT;

    private final float[] particles;
    // private final VertexArray vertexArray;
    private final int maxParticleCount;
    private int currentParticleCount;
    private int nextParticle = 0;

    // Used for VBO
    private int[] vaoID;
    private int[] vboID = new int[1];

    private FloatBuffer vertexArrayBuffer;

    private int dataOffset = 0;

    public ParticleSystem(int maxParticleCount) {
        particles = new float[maxParticleCount * TOTAL_COMPONENT_COUNT];
        this.maxParticleCount = maxParticleCount;

        ByteBuffer qbb = ByteBuffer.allocateDirect(maxParticleCount * 4 * TOTAL_COMPONENT_COUNT);

        qbb.order(ByteOrder.nativeOrder());
        vertexArrayBuffer = qbb.asFloatBuffer();


    }

    public void addParticle(Point3 position, int color, Vector3 direction,
                            float particleStartTime) {

        int particleOffset = nextParticle * TOTAL_COMPONENT_COUNT;
        int currentOffset = particleOffset;
        nextParticle++;

        if (currentParticleCount < maxParticleCount) {
            currentParticleCount++;
        }
        if (nextParticle == maxParticleCount) {
            nextParticle = 0;
        }

        particles[currentOffset++] = position.Px;
        particles[currentOffset++] = position.Py;
        particles[currentOffset++] = position.Pz;
        particles[currentOffset++] = Color.red(color) / 255f;
        particles[currentOffset++] = Color.green(color) / 255f;
        particles[currentOffset++] = Color.blue(color) / 255f;
        particles[currentOffset++] = direction.Vx;
        particles[currentOffset++] = direction.Vy;
        particles[currentOffset++] = direction.Vz;
        particles[currentOffset++] = particleStartTime;



        vertexArrayBuffer.position(particleOffset);

        vertexArrayBuffer.put(particles, particleOffset, TOTAL_COMPONENT_COUNT);
        vertexArrayBuffer.position(0);

    }

    public void bindData(ParticleShaderProgram particleProgram) {
        int dataOffset = 0;


        GLES20.glGenBuffers(1, vboID, 0);

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboID[0]);
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,
                vertexArrayBuffer.capacity() * BYTES_PER_FLOAT,
                vertexArrayBuffer, GLES20.GL_DYNAMIC_DRAW);
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);


        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboID[0]);
        GLES20.glEnableVertexAttribArray(particleProgram .getPositionAttributeLocation());
        GLES20.glVertexAttribPointer(particleProgram.getPositionAttributeLocation(), POSITION_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDE, dataOffset);
        dataOffset += POSITION_COMPONENT_COUNT * BYTES_PER_FLOAT;

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboID[0]);
        GLES20.glEnableVertexAttribArray(particleProgram
                .getColorAttributeLocation());
        GLES20.glVertexAttribPointer(
                particleProgram.getColorAttributeLocation(),
                COLOR_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDE,
                dataOffset);
        dataOffset += COLOR_COMPONENT_COUNT * BYTES_PER_FLOAT;

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboID[0]);
        GLES20.glEnableVertexAttribArray(particleProgram
                .getDirectionVectorAttributeLocation());
        GLES20.glVertexAttribPointer(
                particleProgram.getDirectionVectorAttributeLocation(),
                VECTOR_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDE,
                dataOffset);
        dataOffset += VECTOR_COMPONENT_COUNT * BYTES_PER_FLOAT;

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboID[0]);
        GLES20.glEnableVertexAttribArray(particleProgram
                .getParticleStartTimeAttributeLocation());
        GLES20.glVertexAttribPointer(
                particleProgram.getParticleStartTimeAttributeLocation(),
                PARTICLE_START_TIME_COMPONENT_COUNT, GLES20.GL_FLOAT, false,
                STRIDE, dataOffset);

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
    }

    public void draw(ParticleShaderProgram particleProgram) {
        GLES20.glDrawArrays(GLES20.GL_POINTS, 0, currentParticleCount);

        GLES20.glDeleteBuffers(1, vboID, 0);

        GLES20.glDisableVertexAttribArray(particleProgram
                .getPositionAttributeLocation());
        GLES20.glDisableVertexAttribArray(particleProgram
                .getColorAttributeLocation());
        GLES20.glDisableVertexAttribArray(particleProgram
                .getDirectionVectorAttributeLocation());
        GLES20.glDisableVertexAttribArray(particleProgram
                .getParticleStartTimeAttributeLocation());

    }
}
